package com.xfatm.util.other;

/**
 * id生成器
 * 雪花算法
 *
 */
public class IdGenerator {

    //tableId(0-15)
    private int tableIdBit=4;
    private int tableIdOffsetBit=(63-tableIdBit);
    private long maxTableId=-1^(-1<<tableIdBit);
    private long tableId;

    //机器标识(0-255)
    private int serverIdBit=8;
    private int serverIdOffsetBit=tableIdOffsetBit-serverIdBit;
    private long maxServerId=-1^(-1<<serverIdBit);
    private long serverId;

    //timestamp
    private int timestampBit=41;
    private int timestampOffsetBit=(serverIdOffsetBit-timestampBit);
    private long maxTimestamp=-1L^(-1L<<timestampBit);
    private long timestamp;

    //dataId(0-1023)
    private int dataIdBit=10;
    private long maxDataId=-1L^(-1L<<dataIdBit);
    private long dataId;

    private long startTimestamp=1262275200000L;

    private IdGenerator(int serverId,int tableId){
        if(serverId>maxServerId){
            throw new IllegalArgumentException("serverId最大为"+maxServerId);
        }
        if(tableId>maxTableId){
            throw new IllegalArgumentException("tableId最大为"+maxTableId);
        }
        this.serverId=serverId;
        this.tableId=tableId;
    }

    private int getServerId(long id){
        return (int)(id<<(tableIdBit+1)>>>(64-serverIdBit));
    }

    private int getTableId(long id){
        return (int)((id<<1)>>>(64-tableIdBit));
    }

    public synchronized long nextId(){
        long time=getDiffTimestamp();
        if(time==timestamp){
            dataId++;
        }else{
            dataId=0;
            timestamp=time;
        }
        if(dataId>maxDataId){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return nextId();
        }
        return (
                    tableId<<tableIdOffsetBit
                |serverId<<serverIdOffsetBit
                |timestamp<<timestampOffsetBit
                |dataId
                );
    }

    private long getDiffTimestamp(){
        return System.currentTimeMillis()-startTimestamp;
    }

    public static void main(String[] args){
        IdGenerator idGenerator=new IdGenerator(0,0);
        for(int i=0;i<1000;i++){
            long id=0;
            System.out.println((id=idGenerator.nextId()));
            System.out.println(idGenerator.getServerId(id));
            System.out.println(idGenerator.getTableId(id));
        }
    }
}
